# -*- coding:UTF-8 -*-
# !/usr/bin/env python

import xml.etree.ElementTree as ET
import time, os, sys, shutil
import subprocess, io, csv, re
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr
import configparser
import yaml
import glob
from collections import defaultdict
from db_handler import db_handler

#将结果插入数据库
def insert_test_result(project_id, task_run_id, test_case, result,distributedCount):
    insert_query = """
    INSERT INTO TestResult (project_id, task_run_id, test_case,concurrent, transaction_count, tssuccess_count, tsfail_count, avgtime, tps, susscesrate)
    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
    """
    try:
        db_handler.execute_update(insert_query, (
            project_id, task_run_id, test_case,result['bps']*distributedCount, result['transaction_count'], result['tssuccess_count'], result['tsfail_count'],
            result['avgtime'], result['tps'], result['susscesrate']
        ))
    except Exception as e:
        print(f"Error inserting test result: {e}")

def getResult(fileName, testCase):
    resultAll = {}
    result = {'label': [], 'timeStamp': [], 'elapsed': [], 'success': [], 'allThreads': [], 'time': []}
    beginruntime = 0
    maxruntime = 0
    # transaction_count=0
    tssuccess_count = 0
    tsfail_count = 0
    resultAll["allerrors_list"] = ''
    with open(fileName, 'r', encoding='UTF-8') as csvfile:
        csvreader = csv.reader(csvfile, delimiter=',', quotechar='"')
        for row in csvreader:
            if row[2] == testCase:
                if "label" in result:
                    result["label"].append(row[2])  # 时间戳
                if "timeStamp" in result:
                    result["timeStamp"].append(int(row[0]))  # 时间戳
                if "elapsed" in result:
                    result["elapsed"].append(int(row[1]))  # 响应耗时
                if "success" in result:
                    result["success"].append(row[6])  # 响应成功与失败
                if "allThreads" in result:
                    result["allThreads"].append(int(row[9]))  # 线程
        if result['label']:
            if testCase in result["label"]:
                for key, value in result.items():
                    if key == "timeStamp":
                        beginruntime = min(value)
                        maxruntime = max(value)
                        resultAll["beginruntime"] = beginruntime
                        resultAll["endruntime"] = maxruntime
                    if key == "elapsed":
                        # 计算tps =(sample样本数)/(最后一个线程启动的时间+最后一个线程持续的时间-第一个线程启动的时间)
                        # transaction_count=len(value)
                        # print(transaction_count)
                        endruntime = maxruntime + max(value)
                        totaltime = (endruntime - beginruntime) / 1000
                        tps = round(len(value) / totaltime, 2)
                        resultAll["tps"] = tps
                        resultAll["avgtime"] = format((sum(value) / len(value)), '.2f')
                        ttimeSort = sorted(value)
                        nitylineTime = ttimeSort[round(len(ttimeSort) * 0.9) - 1]
                        resultAll["nitylineTime"] = nitylineTime
                    if key == "allThreads":
                        resultAll["bps"] = max(value)
                    if key == "success":
                        transaction_count = len(value)
                        for s in value:
                            if s == "true":
                                tssuccess_count += 1
                            else:
                                tsfail_count += 1
                        susscesrate = format((tssuccess_count / transaction_count), '.2%')
                        resultAll["transaction_count"] = transaction_count
                        resultAll["tssuccess_count"] = tssuccess_count
                        resultAll["tsfail_count"] = tsfail_count
                        resultAll["susscesrate"] = susscesrate
            else:
                print(time.strftime("%Y-%m-%d %H:%M:%S",
                                    time.localtime()) + ":" + "无法解析 {0} 结果，请检查测试脚本JMX名称与事务控制名称是否一致！ ".format(fileName))
                resultAll["error"] = "true"
                resultAll["tps"] = 0
                resultAll["avgtime"] = 0
                resultAll["nitylineTime"] = 'N/A'
                resultAll["bps"] = 'N/A'
                resultAll["transaction_count"] = 'N/A'
                resultAll["tssuccess_count"] = 'N/A'
                resultAll["tsfail_count"] = 'N/A'
                resultAll["susscesrate"] = 'N/A'
                resultAll["beginruntime"] = beginruntime
                resultAll["endruntime"] = maxruntime
        else:
            print(time.strftime("%Y-%m-%d %H:%M:%S",
                                time.localtime()) + ":" + "无法解析 {0} 结果，请检查JTL是否正常！ ".format(fileName))
            resultAll["error"] = "true"
            resultAll["tps"] = 0
            resultAll["avgtime"] = 0
            resultAll["nitylineTime"] = 'N/A'
            resultAll["bps"] = 'N/A'
            resultAll["transaction_count"] = 'N/A'
            resultAll["tssuccess_count"] = 'N/A'
            resultAll["tsfail_count"] = 'N/A'
            resultAll["susscesrate"] = 'N/A'
            resultAll["beginruntime"] = beginruntime
            resultAll["endruntime"] = maxruntime
            #return
            #sys.exit()
    return resultAll

#2024.8.23 统计所有接口明细信息
def get_results_by_label(file_name):
    results = defaultdict(lambda: defaultdict(list))
    with open(file_name, 'r', encoding='UTF-8') as csvfile:
        csvreader = csv.reader(csvfile, delimiter=',', quotechar='"')
        next(csvreader, None)  # 跳过标题行
        for row in csvreader:
            try:
                timestamp = int(row[0])
                elapsed = int(row[1])
                all_threads = int(row[12])
            except ValueError:
                continue  # 跳过包含非整数值的行

            label = row[2]
            results[label]['timeStamp'].append(timestamp)
            results[label]['elapsed'].append(elapsed)
            results[label]['success'].append(row[7] == 'true')
            results[label]['allThreads'].append(all_threads)

    # 计算每个label的统计数据
    stats_by_label = {}
    for label, data in results.items():
        total_time = (max(data['timeStamp']) - min(data['timeStamp'])) / 1000 if data['timeStamp'] else 0
        stats = {
            'transaction_count': len(data['elapsed']),
            'tssuccess_count': sum(data['success']),
            'tsfail_count': len(data['elapsed']) - sum(data['success']),
            'avgtime': sum(data['elapsed']) / len(data['elapsed']) if data['elapsed'] else 0,
            'tps': round(len(data['elapsed']) / total_time,2) if total_time > 0 else 0
        }
        stats['susscesrate'] = f"{stats['tssuccess_count'] / stats['transaction_count']:.2%}" if stats['transaction_count'] else '0.00%'
        stats_by_label[label] = stats

    return stats_by_label

# 添加将接口明细结果插入 InterfaceDetail 表的函数
def insert_interface_detail(project_id, task_run_id,script_id, interface_name, stats):
    insert_query = """
    INSERT INTO InterfaceDetail (
        project_id, 
        task_run_id, 
        script_id, 
        interface_name, 
        transaction_count, 
        success_count, 
        fail_count, 
        avg_response_time, 
        tps, 
        success_rate
    )
    VALUES (%s, %s, %s,%s, %s, %s, %s, %s, %s, %s)
    """
    try:
        # 将成功率从百分比字符串转换为浮点数
        success_rate = float(stats['susscesrate'].rstrip('%')) / 100 if isinstance(stats['susscesrate'], str) else stats['susscesrate']
        
        db_handler.execute_update(insert_query, (
            project_id,
            task_run_id,
            script_id,
            interface_name,
            stats['transaction_count'],
            stats['tssuccess_count'],
            stats['tsfail_count'],
            float(stats['avgtime']),
            float(stats['tps']),
            success_rate
        ))
    except Exception as e:
        print(f"插入接口明细时出错: {e}")

 # 在适当的位置调用 insert_interface_detail 函数，将接口明细数据写入数据库
def process_and_save_interface_details(project_id, task_run_id,script_id, results):
    for interface_name, stats in results.items():
        insert_interface_detail(project_id, task_run_id,script_id, interface_name, stats)

#输出所有接口明细的html报告
def save_results_to_html(results, output_file):
    sorted_results = sorted(results.items(), key=lambda item: item[1]['avgtime'], reverse=True)
    html_content = '''
<html>
<head>
    <meta charset="UTF-8">
    <title>接口明细结果</title>
    <style>
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 40px;
            background-color: #f4f6f9;
        }
        h2 {
            color: #333333;
            text-align: center;
            margin-bottom: 20px;
        }
        .table-container {
            overflow-x: auto;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            border-radius: 8px;
            background-color: #ffffff;
            padding: 20px;
        }
        table { 
            width: 100%; 
            border-collapse: collapse; 
            table-layout: fixed; 
        }
        th, td {
            padding: 12px 15px;
            text-align: left;
            border-bottom: 1px solid #dddddd;
            word-break: break-word; /* 允许单词换行 */
            white-space: normal; /* 允许换行 */
            font-size: 14px;
            position: relative;
        }
        th.interface, td.interface {
            width: 25%;
            background-color: #e8f4fa;
        }
        th.interface {
            background-color: #007BFF;
            color: #ffffff;
        }
        tr:nth-child(even) {
            background-color: #f9fbfc;
        }
        tr:nth-child(odd) {
            background-color: #ffffff;
        }
        tr:hover {
            background-color: #f1f1f1;
        }
        th { 
            position: sticky;
            top: 0;
            background-color: #007BFF;
            color: #ffffff;
            z-index: 2;
        }
        /* 简化的 Tooltip 样式 */
        .tooltiptext {
            visibility: hidden;
            width: auto;
            max-width: 300px;
            background-color: rgba(0, 0, 0, 0.75);
            color: #fff;
            text-align: left;
            border-radius: 6px;
            padding: 10px;
            position: absolute;
            z-index: 1000;
            bottom: 125%;
            left: 50%;
            transform: translateX(-50%);
            opacity: 0;
            transition: opacity 0.3s;
            word-wrap: break-word;
            white-space: normal;
        }

        /* Tooltip 箭头 */
        .tooltiptext::after {
            content: "";
            position: absolute;
            top: 100%;
            left: 50%;
            margin-left: -5px;
            border-width: 5px;
            border-style: solid;
            border-color: rgba(0, 0, 0, 0.75) transparent transparent transparent;
        }

        /* 显示 Tooltip */
        .tooltip:hover .tooltiptext {
            visibility: visible;
            opacity: 1;
        }

        /* 响应式调整 */
        @media screen and (max-width: 768px) {
            th, td {
                padding: 10px 12px;
                font-size: 12px;
            }
            th.interface, td.interface {
                width: 30%;
            }
            .tooltiptext {
                max-width: 250px;
            }
        }
    </style>
</head>
<body>
    <h2>接口明细结果</h2>
    <div class="table-container">
        <table>
            <tr>
                <th class="interface">接口</th>
                <th>样本总数</th>
                <th>成功数</th>
                <th>失败数</th>
                <th>平均响应时间(ms)</th>
                <th>TPS</th>
                <th>成功率</th>
            </tr>
'''
    for label, stats in sorted_results:
        # 直接显示完整接口名称，无需截断
        html_content += f'''
            <tr>
                <td class="interface">{label}</td>
                <td>{stats['transaction_count']}</td>
                <td>{stats['tssuccess_count']}</td>
                <td>{stats['tsfail_count']}</td>
                <td>{stats['avgtime']:.2f}</td>
                <td>{stats['tps']:.2f}</td>
                <td>{stats['susscesrate']}</td>
            </tr>
'''
    html_content += '''
        </table>
    </div>
</body>
</html>
'''
    with open(output_file, 'w', encoding='UTF-8') as file:
        file.write(html_content)


# 处理错误的结果信息
# def getErrorResult(file):
#     tree = ET.ElementTree()
#     tree.parse(file)
#     root = tree.getroot()
#     allerrors_list = []
#     resultAllErrors = {}
#     for child in root.findall("httpSample"):
#         err = {}
#         # 旧实现方式
#         # for child in root:
#         #     if child.get("s") == "false" and child.get("rm") == "":
#         #         err = {}
#         #         for child1 in child:  # 遍历httpsample下所有节点
#         #             err["name"] = child.get("lb")
#         #             err[child1.tag] = child1.text
#         #             allerrors_list.append(err)
#
#         for child1 in child:  # 遍历httpsample下所有节点
#             err["name"] = child.get("lb")
#             # if child1.tag==("responseData","queryString","java.net.URL","assertionResult"):
#             if child1.tag == "responseData":
#                 err["responseData"] = child1.text
#             if child1.tag == "queryString":
#                 err["queryString"] = child1.text
#             if child1.tag == "java.net.URL":
#                 err["java.net.URL"] = child1.text
#             # if child1.tag=="assertionResult":
#             #     for child2 in child1:
#             #         if child2.tag=="failureMessage":
#             #             err["failureMessage"]=child2.text
#             # err[child1.tag] = child1.text
#
#             # if err in allerrors_list:
#             #     continue
#             # else:
#             allerrors_list.append(err)
#             # print(allerrors_list)
#     resultAllErrors["allerrors_list"] = allerrors_list
#     return resultAllErrors


def getErrorResult(file):
    tree = ET.parse(file)  # 更简洁的方式来加载和解析XML文件
    root = tree.getroot()
    allerrors_list = []
    resultAllErrors = {}

    # 只选择那些属性s="false"的httpSample元素
    for sample in root.findall(".//httpSample[@s='false']"):
        err = {
            "name": sample.get("lb"),  # 获取并设置错误名称
            "rc": sample.get("rc")  # 获取状态码
        }

        # 直接在sample下查找特定子元素，避免不必要的循环
        responseData = sample.find("responseData")
        if responseData is not None and responseData.text is not None:
            err["responseData"] = responseData.text
        else:
            err["responseData"] = "None"  # 为None时，设置默认值

        queryString = sample.find("queryString")
        if queryString is not None:
            err["queryString"] = queryString.text

        url = sample.find("java.net.URL")
        if url is not None:
            err["java.net.URL"] = url.text

        # 处理断言结果，获取失败消息
        assertionResult = sample.find("assertionResult/failureMessage")
        if assertionResult is not None:
            err["failureMessage"] = assertionResult.text

        allerrors_list.append(err)  # 将构建好的错误信息添加到列表中

    resultAllErrors["allerrors_list"] = allerrors_list
    return resultAllErrors


class Template_HTML(object):
    """html报告"""
    HTML_TMPL = """
<!DOCTYPE html>
<html>
    <head>
        <title>性能测试结果</title>
        <style type="text/css">
            body {
                font:normal 12pt verdana,arial,helvetica;
                color:#000000;
            }
            table tr td, table tr th {
                font-size: 12pt;
                word-break: break-all;
                table-layout:fixed;
            }
            table.details tr th{
                color: #ffffff;
                font-weight: bold;
                text-align:center;
                background:#003D79;
                word-break: break-all;
                table-layout:fixed;
            }
            table.details tr td{
                background:#eeeee0;
                word-break: keep-all;
                table-layout:fixed;
            }
            h1 {
                margin: 0px 0px 5px; font: 165%% verdana,arial,helvetica
            }
            h2 {
                margin-top: 1em; margin-bottom: 0.5em; font: bold 125%% verdana,arial,helvetica
            }
            h3 {
                margin-bottom: 0.5em; font: bold 12pt verdana,arial,helvetica
            }
            .Failure {
                font-weight:bold; color:red;
            }


            img
            {
              border-width: 0px;
            }

            .expand_link
            {
               position=absolute;
               right: 0px;
               width: 27px;
               top: 1px;
               height: 27px;
            }

            .page_details
            {
               display: none;
            }

                            .page_details_expanded
                            {
                                display: block;
                                display/* hide this definition from  IE5/6 */: table-row;
                            }
            .page_errors
            {
               display: none;
            }

                            .page_errors_expanded
                            {
                                display: block;
                                display/* hide this definition from  IE5/6 */: table-row;
                            }

        </style>
        <script language="JavaScript">

            function expand(details_id)
            {

                document.getElementById(details_id).className = "page_details_expanded";
            }

            function collapse(details_id)
            {

                document.getElementById(details_id).className = "page_details";
            }

            function change(details_id)
            {
                var _dataType=document.getElementById(details_id+"_image").getAttribute('data-type');
                if(_dataType=='expand')
                {
                    <!-- document.getElementById(details_id+"_image").src = "collapse.png";  -->
                    document.getElementById(details_id+"_image").src = "";
                    expand(details_id);
                    document.getElementById(details_id+"_image").setAttribute('data-type','collapse');
                }
                else
                {
                    <!-- document.getElementById(details_id+"_image").src = "expand.png"; -->
                    document.getElementById(details_id+"_image").src = "";
                    collapse(details_id);
                    document.getElementById(details_id+"_image").setAttribute('data-type','expand');
                } 
            }


            function clock()
            {
                var time = new Date();
                var year = time.getFullYear();
                var month = time.getMonth() + 1;
                var day = time.getDate();
                var hours = time.getHours();
                var min = time.getMinutes();
                var sec = time.getSeconds();
                var mydate= year + "/" + month + "/" + day + " " + hours + ":" + min + ":" + sec ;
                return  mydate;
            }					
        </script>
    </head>
    <body>
        <b id="runtime"></b>
        <b><font color="#0B610B">测试时间</font></b>
        <hr size="2" width="100%%" align="left">
        <table width="100%%" cellpadding="0" cellspacing="0"  style="font-size: 11pt; font-family: verdana,arial,helvetica">
            <tbody> 
                <tr>			  
                    <li>开始时间 ：%(startTime)s</li>    
                    <li>结束时间 ：%(endTime)s</li>       
                </tr>	
            </tbody>
        </table>
        <hr size="2" width="100%%" align="left">
        <font size="4">
            <h1 align="center">
                <b><font color="#0B610B">结果概要</font></b>
            </h1>
        </font>
        <table width="75%%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
            <tbody>
                <tr valign="top">
                    <th>用例总数</th>
                    <th>达标用例数</th>
                    <th>响应时间不达标</th>
                    <th>事务通过率不达标</th>
                    <th>性能下降(20%%)用例数</th>
                    <th>通过率</th>
                </tr>
                <tr valign="top">
                    <td align="center">%(caseCount)s</td>
                    <td align="center">%(passCaseCount)s</td>
                    <td align="center" style="color:%(avgfailedCountcolor)s">%(avgfailedCount)s</td>
                    <td align="center" style="color:%(ratefailedCountcolor)s">%(ratefailedCount)s</td>
                    <td align="center" style="color:%(degradationCountcolor)s">%(degradationCount)s</td>
                    <td align="center" style="color:%(passRatecolor)s">%(passRate)s</td>
                </tr>
            </tbody>
        </table>
        <hr size="2" width="100%%" align="left">
        <h1 align="center">
            <b><font color="#0B610B">详细测试结果</font></b>
        </h1>
        <hr size="2" width="100%%" align="left" />
        <table width="100%%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
            <tbody>
                <tr valign="top">
                    <th>功能名称</th>
                    <th>并发数</th>
                    <th>事务总数</th>
                    <th>失败事务数</th>
                    <th>事务成功率</th>
                    <th>平均响应时间</th>
                    <th>上一版平均响应时间</th>
                    <th>响应时间指标</th>
                    <th>90%% Line</th>
                    <th>TPS</th>
                    <th>上一版TPS</th>
                    <th>接口明细</th>
                    <th style="display:%(gridhide)s;">资源利用率</th>
                    <th>监控图表</th></tr>                
                %(rusult)s
            </tbody>
        </table>
        %(text)s                                 
        %(detail)s 
    </body>
</html>
    """
    result_TMPL = """
        <tr valign="top">
            <td align="left" valign="middle"><a %(errhref)s>%(testCase)s</a></td>
            <td align="center" valign="middle">%(bfs)s</td>
            <td align="center" valign="middle">%(transaction_count)s</td>
            <td align="center" valign="middle">%(tsfail_count)s</td>
            <td align="center" valign="middle" style="color:%(ratecolor)s">%(susscesrate)s</td>
            <td align="center" valign="middle" style="color:%(timecolor)s">%(avgtime)s ms</td>
            <td align="center" valign="middle" >%(lastavgtime)s ms</td>
            <td align="center" valign="middle">%(targettime)s ms</td>   
            <td align="center" valign="middle">%(nitylineTime)s ms</td>
            <td align="center" valign="middle">%(tps)s/s</td>
            <td align="center" valign="middle">%(lasttps)s/s</td>
            <td align="center" valign="middle"><a href="%(reportdetailhtml)s">查看</td>
            <td  style="display: %(gridhide)s; white-space: pre-line;" align="left" valign="middle" width="50">%(resource)s</td>
            <td align="center" valign="middle">
                <a href="javascript:change('page_details_%(testCase)s')">
                    <img alt="expand/collapse" src="" id="page_details_%(testCase)s_image">
                </a>
            </td>
        </tr>
        <tr class="page_details" id="page_details_%(testCase)s">
            <td bgcolor="#FF0000" colspan="13">
                <div>
                        <table align="center" width="100%%" cellspacing="2" cellpadding="5" border="0" bgcolor="#2674A6" bordercolor="#000000">
                            <tbody>
                                <tr>
                                    <td align="center">
                                        <h2 align="center">ResponseTimesOverTime</h2>
                                        <div align="center">
                                            <img src="%(testCase)s_kpi.png">
                                        </div>
                                        </td>
                                    <td align="center">
                                        <h2 align="center">TPS</h2>
                                        <div align="center">
                                            <img src="%(testCase)s_kpi_tps.png">
                                        </div>
                                    </td>
                                </tr>
                                <tr style="display: %(gridhide)s;">
                                    <td align="center">
                                        <h2 align="center">CPU</h2>
                                        <div align="center">
                                            <img src="%(testCase)s_cpu.png">
                                        </div>
                                        </td>
                                    <td align="center">
                                        <h2 align="center">Memory</h2>
                                        <div align="center">
                                            <img src="%(testCase)s_memory.png">
                                        </div>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                </div>
            </td></tr>
    """
    detail_TMPL = """
    <table width="100%%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
        <tbody>
            <tr valign="top">
                <th align="center">用例名称</th>
                <th align="center">展开错误列表</th>
            </tr>
            %(errors_detail)s      
        </tbody>
    </table> 
    """
    errors_detail = """
            <div id="%(testCase)s"><td align="left" >%(testCase)s</td></div>
            <td align="center">
                <a href="javascript:change('page_errors_%(testCase)s')">
                    <img alt="expand/collapse" src="" id="page_errors_%(testCase)s_image" >
                </a>
            </td>
            <tr class="page_errors" id="page_errors_%(testCase)s">
                <td bgcolor="#FF0000" colspan="11">
                    <div >
                            <table style="table-layout:fixed;" width="100%%" cellspacing="2" cellpadding="5" border="0" align="center" bgcolor="#2674A6" bordercolor="#000000">                            
                                <tbody>
                                    <tr valign="top">
                                        <th align="center">HttpName</th>
                                        <th align="center">HttpCode</th>
                                        <th align="center">QueryString</th>
                                        <th align="center">ResponseData</th>
                                        <!-- th align="center">Failure Message</th -->
                                    </tr>
                                    %(detail_tr)s
                                </tbody>
                            </table>
                    </div>
                </td>
            </tr>  
        """
    detail_tr = """
                <tr>
                    <td style="word-break:normal; overflow:auto;">%(HttpName)s</td>
                    <td style="word-break:normal; overflow:auto;">%(HttpCode)s</td>
                    <td style="word-break:normal; overflow:auto;">%(QueryString)s</td>
                    <td style="word-break:normal; overflow:auto;">%(ResponseData)s</td>
                    <!-- td style="font-size: 0.5pt;word-break:normal; overflow:auto;">FailureMessage</td -->
                </tr>
            """


class Template_emailHTML(object):
    """html报告"""
    HTML_TMPL = """
<!DOCTYPE html>
<html>
    <head>
        <title>性能测试结果</title>
        <style type="text/css">
            body {
                font:normal 12pt verdana,arial,helvetica;
                color:#000000;
            }
            table tr td, table tr th {
                font-size: 12pt;
                word-break: break-all;
                table-layout:fixed;
            }
            table.details tr th{
                color: #ffffff;
                font-weight: bold;
                text-align:center;
                background:#003D79;
                word-break: break-all;
                table-layout:fixed;
            }
            table.details tr td{
                background:#eeeee0;
                word-break: keep-all;
                table-layout:fixed;
            }
            h1 {
                margin: 0px 0px 5px; font: 165%% verdana,arial,helvetica
            }
            h2 {
                margin-top: 1em; margin-bottom: 0.5em; font: bold 125%% verdana,arial,helvetica
            }
            h3 {
                margin-bottom: 0.5em; font: bold 12pt verdana,arial,helvetica
            }
            .Failure {
                font-weight:bold; color:red;
            }


            img
            {
              border-width: 0px;
            }

            .expand_link
            {
               position=absolute;
               right: 0px;
               width: 27px;
               top: 1px;
               height: 27px;
            }

            .page_details
            {
               display: none;
            }

                            .page_details_expanded
                            {
                                display: block;
                                display/* hide this definition from  IE5/6 */: table-row;
                            }
            .page_errors
            {
               display: none;
            }

                            .page_errors_expanded
                            {
                                display: block;
                                display/* hide this definition from  IE5/6 */: table-row;
                            }

        </style>
    </head>
    <body>
            <b id="runtime"></b>
        <b><font color="#0B610B">测试时间</font></b>
        <hr size="2" width="100%%" align="left">
        <table width="100%%" cellpadding="0" cellspacing="0"  style="font-size: 11pt; font-family: verdana,arial,helvetica">
            <tbody> 
                <tr>			  
                    <li>开始时间 ：%(startTime)s</li>    
                    <li>结束时间 ：%(endTime)s</li>       
                </tr>	
            </tbody>
        </table>
        <hr size="2" width="100%%" align="left">
        <font size="4">
            <h1 align="center">
                <b><font color="#0B610B">结果概要</font></b>
            </h1>
        </font>
        <table width="75%%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
            <tbody>
                <tr valign="top">
                    <th>用例总数</th>
                    <th>达标用例数</th>
                    <th>响应时间不达标</th>
                    <th>事务通过率不达标</th>
                    <th>性能下降(20%%)用例数</th>
                    <th>通过率</th>
                </tr>
                <tr valign="top">
                    <td align="center">%(caseCount)s</td>
                    <td align="center">%(passCaseCount)s</td>
                    <td align="center" style="color:%(avgfailedCountcolor)s">%(avgfailedCount)s</td>
                    <td align="center" style="color:%(ratefailedCountcolor)s">%(ratefailedCount)s</td>
                    <td align="center" style="color:%(degradationCountcolor)s">%(degradationCount)s</td>
                    <td align="center" style="color:%(passRatecolor)s">%(passRate)s</td>
                </tr>
            </tbody>
        </table>
        <hr size="2" width="100%%" align="left">
        <h1 align="center">
             <b><font color="#0B610B">详细测试结果</font></b>
        </h1>
        <hr size="2" width="100%%" align="left" />
        <table width="100%%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
            <tbody>
                <tr valign="top">
                    <th>功能名称</th>
                    <th>并发数</th>
                    <th>事务总数</th>
                    <th>失败事务数</th>
                    <th>事务成功率</th>
                    <th>平均响应时间</th>
                    <th>上一版平均响应时间</th>
                    <th>响应时间指标</th>
                    <th>90%% Line</th>
                    <th>TPS</th>
                    <th>上一版TPS</th>
                    <th style="display:%(gridhide)s;">资源利用率</th>           
                %(rusult)s
            </tbody>
        </table>                                           
    </body>
</html>
    """
    result_TMPL = """
        <tr valign="top">
            <td align="left" valign="middle"><a>%(testCase)s</a></td>
            <td align="center" valign="middle">%(bfs)s</td>
            <td align="center" valign="middle">%(transaction_count)s</td>
            <td align="center" valign="middle">%(tsfail_count)s</td>
            <td align="center" valign="middle" style="color:%(ratecolor)s">%(susscesrate)s</td>
            <td align="center" valign="middle" style="color:%(timecolor)s">%(avgtime)s ms</td>
            <td align="center" valign="middle">%(lastavgtime)s ms</td>
            <td align="center" valign="middle">%(targettime)s ms</td>
            <td align="center" valign="middle">%(nitylineTime)s ms</td>
            <td align="center" valign="middle">%(tps)s/s</td>
            <td align="center" valign="middle">%(lasttps)s/s</td>
            <td  style="display: %(gridhide)s; white-space: pre-line;" align="left" valign="middle" width="50">%(resource)s</td>
        </tr>
    """
    # 方法一


class Template_email(object):
    mailcontent = '''
     <!DOCTYPE html> 
     <html>    
     <head>    
     <meta charset="UTF-8">    
     <title>自动化性能测试结果</title>    
     </head>          
     <body leftmargin="0" marginwidth="0" topmargin="8" marginheight="4" offset="0">    
         <table width="100%%" cellpadding="0" cellspacing="0"  style="font-size: 11pt; font-family: verdana,arial,helvetica">    
             <tr>                   
                 大家好，%(projectName)s %(date)s 自动性能测试结果如下。</br> 
             </tr>    
             <tr>    
                 <td>    
                 <b><font color="#0B610B">测试环境信息</font></b>
                 <hr size="2" width="100%%" align="left" /></td>
       <tr>    
                 <td>    
                     <ul>
                         <li>产品名称：%(projectName)s</li>
                         <li>程序版本：%(version)s</li>
                         %(jenkinsaddr)s
                         <li>应用服务地址：<a href="%(ulr)s">%(ulr)s</a></li>    
                         <li>数据库地址：%(db)s</li> 
                         <li>详细报告：<a href="%(fullReport)s">%(fullReport)s</a></li>      
                     </ul>    
                 </td>    			
             </tr>    
            </tr>         
         </table> 
             <div>
                 %(emailResult)s
             </div>     
     </body>    
     </html>
     '''


def DealRepeat(data, key):
    new_data = []  # 用于存储去重后的list
    values = []  # 用于存储当前已有的值
    for d in data:
        if d[key] not in values:
            new_data.append(d)
            values.append(d[key])
    return new_data

    # 方法二


def DealRepeat2(data):
    immutable_dict = set([str(item) for item in data])
    data = [eval(i) for i in immutable_dict]
    return data


def DealResource(fileName):
    result = {}
    with open(fileName, 'r') as csvfile:
        csvreader = csv.reader(csvfile, delimiter=',', quotechar='"')
        for i, row in enumerate(csvreader):
            if i == 0:
                if row[0] != "timeStamp":
                    print(
                        time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "{0}解析失败，请确认jtl文件是否为csv格式！".format(
                            fileName))
                    return
            else:
                if row[1] != "elapsed" and int(row[1]) >= 0:
                    if row[2] in result:
                        result[row[2]].append(int(row[1]))
                    else:
                        result[row[2]] = [int(row[1])]
                else:
                    print(
                        time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "{0}解析失败，请确认资源监控是否正常收集数据！".format(
                            fileName))
                    break
        for key, value in result.items():
            # print(key + '平均利用率:' + format((sum(value) / 1000 / len(value)/100), '.2%'))
            result[key] = format((sum(value) / 1000 / len(value) / 100), '.2%')
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "{0}解析完成！".format(fileName))
    return result


# def gettargettime(yamlfile):
#     targettimedict={}
#     testconfig = yaml.load(io.open(yamlfile, 'r', encoding='utf-8'),Loader=yaml.FullLoader)
#     for i in range(len(testconfig['execution'])):
#         if "targettime" in str(testconfig['execution'][i]):
#             targettime=str(testconfig['execution'][i]['targettime'])
#             if targettime.find("ms")!=-1:
#                 targettimedict[testconfig['execution'][i]['scenario']] = targettime.split("ms")[0]
#             else:
#                 targettimedict[testconfig['execution'][i]['scenario']] = targettime
#         # targettime=testconfig['execution'][i]['targettime']
#     return targettimedict

# 从yaml文件内获取指定的数据，如响应时间、上一版本响应时间、TPS等

def get_key_yamlfile(yamlfile, key_name):
    target_time_dict = {}
    testconfig = yaml.load(io.open(yamlfile, 'r', encoding='utf-8'), Loader=yaml.FullLoader)
    for execution in testconfig['execution']:
        if key_name in execution:
            if key_name == 'distributed':
                target_time_dict[execution['scenario']] = len(execution[key_name])
            else:
                target_time = str(execution[key_name])
                if "ms" in target_time:
                    target_time_dict[execution['scenario']] = target_time.split("ms")[0]
                else:
                    target_time_dict[execution['scenario']] = target_time
    return target_time_dict


# 修改yaml文件内的数据
def modify_scenario_attributes(yamlfile, scenario_name, key, value):
    # 读取 YAML 文件
    with io.open(yamlfile, 'r', encoding='utf-8') as file:
        testconfig = yaml.safe_load(file)

    # 查找并修改对应场景的指定键值
    for execution in testconfig['execution']:
        if execution.get('scenario') == scenario_name:
            execution[key] = value
            break  # 假设每个场景名称是唯一的，找到后即可退出循环

    # 将修改后的内容写回 YAML 文件
    with io.open(yamlfile, 'w', encoding='utf-8') as file:
        yaml.safe_dump(testconfig, file, default_flow_style=False, allow_unicode=True, sort_keys=False)


# def getimage(jmeterHome, jtlDir, pngsaveDir):
#     jmhome = jmeterHome  # r'D:\CXJC\apache-jmeter-5.2.1'
#     jtldir = jtlDir  # r'D:\CXJC\Taurus\umcNew\jtl3'
#     pngdir = pngsaveDir
#     panfu = jtldir.split(":")[0]
#     bat_name = 'getimage.bat'
#     s1 = ''' @ECHO OFF
# setlocal EnableDelayedExpansion
# {0}:
# cd {1}
# for /r %%i in (*_cpu.jtl) do (java -jar {2}\lib\ext\CMDRunner.jar --tool Reporter --input-jtl %%i --plugin-type PerfMon --width 800 --height 500 --generate-png {3}\%%~ni.png)
# for /r %%i in (*_memory.jtl) do (java -jar {2}\lib\ext\CMDRunner.jar --tool Reporter --input-jtl %%i --plugin-type PerfMon --width 800 --height 500 --generate-png {3}\%%~ni.png)
# for /r %%i in (*_kpi.jtl) do (java -jar {2}\lib\ext\CMDRunner.jar --tool Reporter --input-jtl %%i --plugin-type TransactionsPerSecond --width 800 --height 500 --generate-png {3}\%%~ni_tps.png)
# for /r %%i in (*_kpi.jtl) do (java -jar {2}\lib\ext\CMDRunner.jar --tool Reporter --input-jtl %%i --plugin-type ResponseTimesOverTime --width 800 --height 500 --generate-png {3}\%%~ni.png)
#      '''.format(panfu, jtldir, jmhome, pngdir)
#     # 写入一个临时文件
#     f = open(bat_name, 'w',encoding="utf-8")
#     f.write(s1)
#     f.close()
#
#     p = subprocess.Popen("cmd.exe /c" + bat_name, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
#     curline = p.stdout.readline()
#     while (curline != b''):
#         print(curline)
#         curline = p.stdout.readline()
#     p.wait()
#     os.remove(bat_name)

def generate_chart(jtl_file, jmhome, pngdir, chart_type, pngname):
    cmd = [
        'java', '-jar', os.path.join(jmhome, 'lib', 'ext', 'CMDRunner.jar'),
        '--tool', 'Reporter',
        '--input-jtl', jtl_file,
        '--plugin-type', chart_type,
        '--width', '800',
        '--height', '600',
        '--generate-png', os.path.join(pngdir, pngname + ".png")
        # f"{os.path.splitext(os.path.basename(jtl_file))[0]}.png")
    ]
    try:
        subprocess.check_call(cmd)
        print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + f"执行图表生成：{jtl_file}")
    except subprocess.CalledProcessError as e:
        print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + f"图表生成异常： {jtl_file}: {e}")


def getimage(jmeterHome, jtlDir, pngsaveDir):
    jmhome = jmeterHome
    jtldir = jtlDir
    pngdir = pngsaveDir

    for jtl_file in glob.glob(os.path.join(jtldir, '*_cpu.jtl')):
        generate_chart(jtl_file, jmhome, pngdir, 'PerfMon', os.path.splitext(os.path.basename(jtl_file))[0])
    for jtl_file in glob.glob(os.path.join(jtldir, '*_memory.jtl'), ):
        generate_chart(jtl_file, jmhome, pngdir, 'PerfMon', os.path.splitext(os.path.basename(jtl_file))[0])
    for jtl_file in glob.glob(os.path.join(jtldir, '*_kpi.jtl')):
        generate_chart(jtl_file, jmhome, pngdir, 'TransactionsPerSecond',
                       os.path.splitext(os.path.basename(jtl_file))[0] + "_tps")
        generate_chart(jtl_file, jmhome, pngdir, 'ResponseTimesOverTime',
                       os.path.splitext(os.path.basename(jtl_file))[0])


class ReadConfig:
    """定义一个读取配置文件的类"""

    def __init__(self, filepath=None):
        if filepath:
            configpath = filepath
        else:
            print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "未找到config.ini配置文件，请确认！")
            sys.exit()
            # runpath = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + os.path.sep + ".")
            # configpath = os.path.join(runpath, "config.ini")
        self.cf = configparser.ConfigParser()
        self.cf.read(configpath, encoding="utf-8-sig")

    def get_TestInfo(self, param):
        value = self.cf.get("TestInfo", param)
        return value

    def get_EmailInfo(self, param):
        value = self.cf.get("EmailInfo", param)
        return value


def sendEmail(reportdir, configpath, jkBUILD_ID=0):
    # reportdir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'report')
    html_email = Template_email()
    emailResult = open(reportdir + r'\EmailReport.html', 'r', encoding="utf-8")
    htmlcont = emailResult.read()
    today = time.strftime('%Y-%m-%d', time.localtime(time.time()))
    emailout = ""
    RDC = ReadConfig(configpath)
    projectName = RDC.get_TestInfo("projectName")
    version = RDC.get_TestInfo("version")
    jenkinsUrl = RDC.get_TestInfo("jenkinsUrl")
    ulr = RDC.get_TestInfo("webUrl")
    db = RDC.get_TestInfo("DB")
    fullReport = RDC.get_TestInfo("fullReport")
    if jenkinsUrl != "" and jkBUILD_ID != 0:
        jenkinsaddr = r'<li>详细测试结果：<a href="%(jenkinsUrl)s/%(jkBUILD_ID)s/HTML_20Report/">%(jenkinsUrl)s/%(jkBUILD_ID)s/HTML_20Report/</a></li>'
        emailout = html_email.mailcontent % dict(projectName=projectName, version=version, date=today, ulr=ulr, db=db,
                                                 fullReport=fullReport,
                                                 jenkinsaddr=jenkinsaddr, emailResult=htmlcont)
        emailout = emailout.replace(r"%(jenkinsUrl)s", jenkinsUrl).replace(r"%(jkBUILD_ID)s", str(jkBUILD_ID))
    else:
        jenkinsaddr = ""
        emailout = html_email.mailcontent % dict(projectName=projectName, version=version, date=today, ulr=ulr, db=db,
                                                 fullReport=fullReport,
                                                 jenkinsaddr=jenkinsaddr, emailResult=htmlcont)
    from_name = RDC.get_EmailInfo("from_name")
    from_addr = RDC.get_EmailInfo("from_addr")
    password = RDC.get_EmailInfo("password")
    to_addr = RDC.get_EmailInfo("to_addr")
    cc_addr = RDC.get_EmailInfo("cc_addr")
    smtp_server = RDC.get_EmailInfo("smtp_server")
    subject = RDC.get_EmailInfo("subject")
    if len(from_addr) == 0 or len(password) == 0 or len(to_addr) == 0:
        print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "邮件发送失败，请检查配置！")
        return
    else:
        # 邮箱正文内容，第一个参数为内容，第二个参数为格式(plain 为纯文本)，第三个参数为编码
        msg = MIMEText(emailout, 'html', 'utf-8')
        # 邮件头信息
        msg['From'] = formataddr([from_name, from_addr], 'utf-8')  # Header(from_addr)
        To_addr_list = to_addr.split(';')
        Cc_addr_list = cc_addr.split(';')
        msg['To'] = ','.join(To_addr_list)
        msg['Cc'] = ','.join(Cc_addr_list)
        msg['Subject'] = Header(subject)
        try:
            # 开启发信服务，这里使用的是加密传输
            server = smtplib.SMTP_SSL(host=smtp_server)
            server.connect(smtp_server, 465)
            # 登录发信邮箱
            server.login(from_addr, password)
            # 发送邮件
            server.sendmail(from_addr, To_addr_list + Cc_addr_list, msg.as_string())
            # 关闭服务器
            server.quit()
            print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "邮件发送成功")
            return True
        except smtplib.SMTPException:
            print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "邮件发送失败")
            return False


def jtltoHTML(jmeterHome, jtlpath, yamlfile, project_id=None, task_run_id=None,jkbuildid=0):
    reportbetintime = 0
    if not os.path.exists(jtlpath):
        print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "jtl文件路径不存在,无法解析结果!")
        sys.exit()
    else:
        reportdirtime = time.strftime('%Y%m%d-%H%M%S')
        # reportdir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'report')
        configpath = os.path.join(os.path.join(os.path.dirname(jtlpath), 'config'), 'config.ini')
        reportdir = os.path.join(os.path.dirname(jtlpath), 'report')
        # logdir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'log')
        if os.path.isdir(reportdir):
            os.rename(reportdir, reportdir + "bak" + reportdirtime)
            os.mkdir(reportdir)
        else:
            os.mkdir(reportdir)
        # if not os.path.isdir(logdir):
        #     os.mkdir(logdir)
        oldname1 = os.path.split(os.path.realpath(__file__))[0] + "\\" + "collapse.png"
        oldname2 = os.path.split(os.path.realpath(__file__))[0] + "\\" + "expand.png"
        newname1 = reportdir + "\\" + "collapse.png"
        newname2 = reportdir + "\\" + "expand.png"
        if os.path.exists(oldname1) and os.path.exists(oldname2):
            shutil.copyfile(oldname1, newname1)
            shutil.copyfile(oldname2, newname2)

        files = os.listdir(jtlpath)
        jtl_prefix = '.jtl'
        html = Template_HTML()
        html_email = Template_emailHTML()
        result_html = ''
        result_emailhtml = ''
        detail_TMPL = ''
        error_tab = ''
        filenamelist = []
        text = ''
        reportendtime = 1
        resultAllErrors = {}
        caseCount = 0  # 用例总数
        passCaseCount = 0  # 达标用例数
        avgfailedCount = 0  # 响应时间超标数
        ratefailedCount = 0  # 失败率不达标数量
        degradationCount = 0  # 性能下降个数
        # 获取所有场景响应时间指标
        targettimedict = get_key_yamlfile(yamlfile, 'targettime')
        # 获取所有场景上一次测试结果
        lastavgtimedict = get_key_yamlfile(yamlfile, 'lastavgtime')
        lasttpsdict = get_key_yamlfile(yamlfile, 'lasttps')
        # 获取分布式执行机器个数
        distributeddict = get_key_yamlfile(yamlfile, 'distributed')

        for filename1 in files:
            prefix = os.path.splitext(filename1)[1]
            if prefix in jtl_prefix:
                # if filename1.find("cpu")==-1 and filename1.find("memory")==-1:
                #     print(len(filename1.split("_")))
                if filename1.find("kpi") != -1:
                    filenamelist.append(filename1)

        # 从 session 中获取 project_id 和 task_run_id


        if len(filenamelist) > 0:
            # 循环处理目录下所有jtl
            for filename in filenamelist:
                print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "正在解析" + filename)
                caseCount += 1
                filenameFull = jtlpath + "\\" + filename
                filenameDetail = filenameFull.split("_kpi.jtl")[0] + ".jtl"
                testCase = filename.split("_kpi.jtl")[0]
                result = getResult(filenameFull, testCase)


                # if filenamelist.index(filename) == 0:
                # reportbetintime = int(round(os.path.getmtime(filenameFull) * 1000))
                # if filenamelist.index(filename) == len(filenamelist) - 1:
                # reportendtime = int(round(os.path.getmtime(filenameFull) * 1000))

                # 处理明细结果报告
                if os.path.exists(filenameDetail):
                    detailReportFileName = testCase + "detail.html"
                    script_query = "SELECT id FROM Script s WHERE s.file_name LIKE %s"
                    script_id_result = db_handler.execute_query(script_query, (f"%{testCase}%",))
                    script_id = script_id_result[0].get("id")
                    results = get_results_by_label(filenameDetail)
                    save_results_to_html(results, os.path.join(reportdir, detailReportFileName))
                    process_and_save_interface_details(project_id, task_run_id,script_id, results)
                else:
                    detailReportFileName = "TestReport.html"

                if result:
                    if filenamelist.index(filename) == 0:
                        reportbetintime = result["beginruntime"]
                    reportendtime = result["endruntime"]

                    CPUresource = {}
                    Memoryresource = {}
                    cpufilename = jtlpath + "\\" + testCase + "_cpu.jtl"
                    memfilename = jtlpath + "\\" + testCase + "_memory.jtl"
                    if os.path.exists(cpufilename) and os.path.exists(memfilename):
                        gridhide = ''
                        if os.path.exists(cpufilename):
                            CPUresource = DealResource(cpufilename)
                        if os.path.exists(memfilename):
                            Memoryresource = DealResource(memfilename)
                    else:
                        gridhide = 'none'
                    # if not bool(CPUresource) or not bool(Memoryresource):
                    # gridhide='none'
                    # else:
                    # gridhide=''
                    #print(gridhide)
                    if result["susscesrate"]!='N/A' and float(result["susscesrate"].strip("%")) < 99.99:
                        ratecolor = "red"
                        ratefailedCount += 1
                    else:
                        ratecolor = "black"

                    # if testCase in targettimedict:
                    #     targettime=int(targettimedict[testCase])
                    #     lastavgtime=float(lastavgtimedict[testCase])
                    #     modify_scenario_attributes(yamlfile, testCase,'lastavgtime', float(result["avgtime"])) #更新yaml中上一版本的平均响应时间的值
                    # else:
                    #     targettime=0
                    #     lastavgtime=0

                    # 与上版本数据对比处理
                    targettime = int(targettimedict.get(testCase, 0))
                    lastavgtime = float(lastavgtimedict.get(testCase, 0.0))
                    lasttps = float(lasttpsdict.get(testCase, 0.0))
                    distributedCount=int(distributeddict.get(testCase, 1))
                    modify_scenario_attributes(yamlfile, testCase, 'lastavgtime', float(result["avgtime"]))
                    modify_scenario_attributes(yamlfile, testCase, 'lasttps', float(result["tps"]))

                    if float(result["avgtime"]) > targettime:
                        timecolor = "red"
                        avgfailedCount += 1
                    # elif lastavgtime != 0 and round(abs((lastavgtime - float(result["avgtime"])) / lastavgtime), 1) >= 0.1:
                    elif lastavgtime != 0 and ((float(result["avgtime"]) - lastavgtime) / lastavgtime) >= 0.2:  # 性能下降20%则标颜色
                        timecolor = "rgb(247, 134, 5)"
                        degradationCount += 1
                    else:
                        timecolor = "black"

                    # if float(result["avgtime"]) > targettime:
                    #     timecolor = "red"
                    #     avgfailedCount += 1
                    #     # 计算性能变化百分比
                    #     if lastavgtime != 0:  # 确保上次平均响应时间不为0，避免除以0的错误
                    #         performance_change_percentage = (float(result["avgtime"]) - lastavgtime) / lastavgtime * 100
                    #         if performance_change_percentage >= 20:  # 如果性能下降20%或以上
                    #             timecolor = "rgb(247, 134, 5)"  # 设置为橙色
                    #             degradationCount += 1  # 性能下降计数加一
                    #         else:
                    #             timecolor = "black"  # 否则设置为黑色
                    #     else:
                    #         timecolor = "black"  # 如果没有上次的数据，也设置为黑色

                    if result["susscesrate"]!='N/A' and float(result["susscesrate"].strip("%")) >= 99.99 and float(result["avgtime"]) < targettime:
                        passCaseCount += 1

                    # 插入测试结果数据到 TestResult 表
                    if project_id and task_run_id:
                        insert_test_result(project_id, task_run_id, testCase, result, distributedCount)
                    else:
                        print("Warning: project_id 或 task_run_id 为空，跳过数据库插入")

                    # 处理错误信息的html结果
                    errorfile = jtlpath + "\\" + testCase + "_error.jtl"
                    if os.path.exists(errorfile):
                        resultAllErrors = getErrorResult(errorfile)
                        # # 将所有错误信息写入本地log
                        # logname = '{testCase}.log'.format(testCase=testCase)
                        # logname=os.path.join(logdir, logname)
                        # with open(logname, 'w', encoding='utf-8') as f:
                        #     f.write(str(resultAllErrors["allerrors_list"]))
                        if len(resultAllErrors["allerrors_list"]) > 0:
                            text = """
                                                <hr size="1"/>
                                                <h1 align="center"><b><font color="#0B610B">详细失败结果（包含事务外请求报错，需关注）</b></font></h1>"""
                            detail_tr = ''
                            # 2023.2.24 优化，将"responseData"传参改为"java.net.URL"，更换去重字段，优化解析效率
                            allerrors = DealRepeat(resultAllErrors["allerrors_list"], "java.net.URL")
                            pattern = re.compile(r'<[^>]+>', re.S)  # 去除html标签
                            if len(allerrors) > 0:
                                for i in range(0, len(allerrors)):
                                    detail_trtmp = html.detail_tr % dict(HttpName=allerrors[i]["java.net.URL"],
                                                                         HttpCode=allerrors[i]["rc"],
                                                                         QueryString=allerrors[i]["queryString"],
                                                                         ResponseData=pattern.sub('', allerrors[i][
                                                                             "responseData"], )
                                                                         )  # ,failureMessage=allerrors[i]["failureMessage"]
                                    detail_tr += detail_trtmp
                                    detail_td = html.errors_detail % dict(testCase=testCase, detail_tr=detail_tr)
                                error_tab += detail_td
                            detail_TMPL = html.detail_TMPL % dict(errors_detail=error_tab)
                    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + filename + " 解析完成！")

                    # 处理html主表内容
                    if resultAllErrors and resultAllErrors["allerrors_list"]:
                        errhref = 'href=#{0}'.format(testCase)
                    else:
                        errhref = ''
                    startTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(reportbetintime / 1000))
                    endTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(reportendtime / 1000))
                    reportTime = time.strftime("%Y%m%d%H%M%S", time.localtime(result["beginruntime"] / 1000))
                    # print(str(CPUresource).replace("{","").replace("}","").replace("'","").replace(",","").replace(" ","").replace("%","%\n")+str(Memoryresource).replace("{","").replace("}","").replace("'","").replace(",","").replace(" ","").replace("%","%\n"))
                    result_td = html.result_TMPL % dict(testCase=testCase, errhref=errhref, bfs=result["bps"] * distributedCount,
                                                        transaction_count=result["transaction_count"],
                                                        tsfail_count=result["tsfail_count"], ratecolor=ratecolor,
                                                        susscesrate=result["susscesrate"],
                                                        resource=str(CPUresource).replace("{", "").replace("}",
                                                                                                           "").replace(
                                                            "'", "").replace(",", "").replace(" ", "").replace("%",
                                                                                                               "%\n") + str(
                                                            Memoryresource).replace("{", "").replace("}", "").replace(
                                                            "'", "").replace(",", "").replace(" ", "").replace("%",
                                                                                                               "%\n"),
                                                        avgtime=result["avgtime"], timecolor=timecolor,
                                                        targettime=targettime, lastavgtime=lastavgtime, lasttps=lasttps,reportdetailhtml=detailReportFileName,
                                                        nitylineTime=result["nitylineTime"], tps=result["tps"],
                                                        gridhide=gridhide)
                    result_html += result_td

                    result_td2 = html_email.result_TMPL % dict(testCase=testCase, bfs=result["bps"] * distributedCount ,
                                                               transaction_count=result["transaction_count"],
                                                               tsfail_count=result["tsfail_count"], ratecolor=ratecolor,
                                                               susscesrate=result["susscesrate"],
                                                               resource=str(CPUresource).replace("{", "").replace("}",
                                                                                                                  "").replace(
                                                                   "'", "").replace(",", "").replace(" ", "").replace(
                                                                   "%", "%\n") + str(Memoryresource).replace("{",
                                                                                                             "").replace(
                                                                   "}", "").replace("'", "").replace(",", "").replace(
                                                                   " ", "").replace("%", "%\n"),
                                                               avgtime=result["avgtime"], timecolor=timecolor,
                                                               targettime=targettime, lastavgtime=lastavgtime,
                                                               lasttps=lasttps,
                                                               nitylineTime=result["nitylineTime"], tps=result["tps"],
                                                               gridhide=gridhide)
                    result_emailhtml += result_td2
                else:
                    continue

            passRate = str(format((passCaseCount / caseCount), '.2%'))
            if avgfailedCount > 0:
                avgfailedCountcolor = "red"
            else:
                avgfailedCountcolor = "black"

            if ratefailedCount > 0:
                ratefailedCountcolor = "red"
            else:
                ratefailedCountcolor = "black"

            if float(str(passRate).strip("%")) < 90:
                passRatecolor = "red"
            else:
                passRatecolor = "black"

            if degradationCount > 0:
                degradationCountcolor = "rgb(247, 134, 5)"
            else:
                degradationCountcolor = "black"

            htmloutput = html.HTML_TMPL % dict(startTime=startTime, endTime=endTime,
                                               avgfailedCountcolor=avgfailedCountcolor,
                                               ratefailedCountcolor=ratefailedCountcolor, passRatecolor=passRatecolor,
                                               degradationCountcolor=degradationCountcolor,
                                               caseCount=caseCount, passCaseCount=passCaseCount,
                                               avgfailedCount=avgfailedCount, ratefailedCount=ratefailedCount,
                                               degradationCount=degradationCount,
                                               passRate=passRate, rusult=result_html, text=text, detail=detail_TMPL,
                                               gridhide=gridhide)
            emailhtmloutput = html_email.HTML_TMPL % dict(startTime=startTime, endTime=endTime,
                                                          avgfailedCountcolor=avgfailedCountcolor,
                                                          ratefailedCountcolor=ratefailedCountcolor,
                                                          degradationCountcolor=degradationCountcolor,
                                                          passRatecolor=passRatecolor, caseCount=caseCount,
                                                          passCaseCount=passCaseCount, avgfailedCount=avgfailedCount,
                                                          degradationCount=degradationCount,
                                                          ratefailedCount=ratefailedCount, passRate=passRate,
                                                          rusult=result_emailhtml, gridhide=gridhide)
            # filename = '{date}_TestReport.html'.format(date=time.strftime('%Y%m%d%H%M%S'))
            filename = 'TestReport.html'
            filename = os.path.join(reportdir, filename)
            # emailfilename = '{date}_EmailReport.html'.format(date=time.strftime('%Y%m%d%H%M%S'))
            emailfilename = 'EmailReport.html'
            emailfilename = os.path.join(reportdir, emailfilename)
            with open(filename, 'wb') as f:
                f.write(htmloutput.encode('utf8'))

            with open(emailfilename, 'wb') as f:
                f.write(emailhtmloutput.encode('utf8'))
        else:
            print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "kpi.jtl文件不存在,无法解析结果!！ ")
            sys.exit()
    if os.path.exists(configpath):
        if sendEmail(reportdir, configpath, jkbuildid):
            print("#####################################################################################")
            print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + " 已完成结果解析并已发送邮件！")
        else:
            print("#####################################################################################")
            print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + " 已完成结果解析但邮件发送失败，请检查邮箱配置！")
    else:
        print("#####################################################################################")
        print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + "邮件发布信息，配置文件不存在！")
    print("#####################################################################################")
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + " 正在生成图表，请稍等......")
    getimage(jmeterHome, jtlpath, reportdir)
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + " 图表已生成完成！")
    print("#####################################################################################")
    print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + ":" + " 已全部完成处理！报告目录为：" + reportdir)


if __name__ == '__main__':
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
    jmhome = sys.argv[1]
    jtlpath = sys.argv[2]
    yamlfile = sys.argv[3]
    project_id = sys.argv[4] if len(sys.argv) > 4 else None
    task_run_id = sys.argv[5] if len(sys.argv) > 5 else None
    jkbuildid = sys.argv[6] if len(sys.argv) > 6 else 0

    #jtltoHTML(jmhome, jtlpath, yamlfile,  project_id, task_run_id,jkbuildid)
    if len(sys.argv) == 7:
        jtltoHTML(jmhome, jtlpath, yamlfile,  project_id, task_run_id, jkbuildid)
    elif len(sys.argv) == 6:
        jtltoHTML(jmhome, jtlpath, yamlfile, project_id, task_run_id)
    else:
        jtltoHTML(jmhome, jtlpath, yamlfile)

    # jmhome = r'D:\worksoft\apache-jmeter-5.3'
    # jtlpath = r"C:\Users\user\Desktop\TPP\jtl"
    # yamlfile = r"C:\Users\user\Desktop\TPP\施工管理项目组shixiuxiu_xsw.yaml"
    # jtltoHTML(jmhome, jtlpath, yamlfile,116,555)

    # get_key_yamlfile(r'C:\Users\user\Desktop\TPP\yaml\TL.yaml','targettime')

    # modify_scenario_attributes(r'C:\Users\user\Desktop\TPP\yaml\TL.yaml','TC01_流程发起','lastavgtime',7788)
